
/*
 * libqueue
 * Copyright (c) 2007 PRAV
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */


/* 0.1.3: Iuri - Adaptacao das queues para uso com multiplos usuarios (saidas)
   0.1.2: Gaspare - Correcao de semaforos em destroy_queue
                    Criacao de um flush unico para flush e destroy
                    Adaptacao para retorno de E_SDL_MUTEX_ERROR quando mutex_P retorna -1
   0.1.1: Iuri - Release inicial
 */

#include <stdio.h>

#include <unistd.h>
#include <resolv.h>
#include <string.h>
#include <time.h>

#include "event_queue.h"
#include "listener.h"


pthread_mutex_t queueMutex;

davint_event_queue_t *davint_event_init_queue(void) {

    davint_event_queue_t *newqueue_p;

    if (!(newqueue_p = (davint_event_queue_t*) malloc(sizeof (davint_event_queue_t))))
        return (NULL);

    //newqueue_p->length = 0;
    //newqueue_p->size = 0;

    newqueue_p->next_buffer = 0;
    newqueue_p->last_buffer = 0;

    /*newqueue_p->actual_internal_buffer = 0;
    newqueue_p->actual_internal_position = 0;

    
    if ((newqueue_p->internal_queue_buffer[0] = (uint8_t*) malloc(QUEUE_BUFFER_SIZE)) == NULL)
        return (NULL);

    if ((newqueue_p->internal_queue_buffer[1] = (uint8_t*) malloc(QUEUE_BUFFER_SIZE)) == NULL)
        return (NULL);*/

    return (newqueue_p);
}

int davint_event_enqueue(davint_event_queue_t *queue_p, uint8_t *buffer_p, uint32_t buffersize, uint32_t timestamp) {
    uint8_t temp;

    // verifica se a queue existe
    if (!queue_p)
        return (E_UNDEFINED_QUEUE);

    pthread_mutex_lock(&queueMutex);

    // verifica disponibilidade de espaço para escrever novos dados
    if (queue_p->next_buffer == QUEUE_BUFFER_TOTAL_NUMBER - 1) temp = 0;
    else temp = queue_p->next_buffer + 1;
    // se ponteiros encostarem a fila encheu. Informa que produtor deve aguardar.
    if (temp == queue_p->last_buffer) {
        pthread_mutex_unlock(&queueMutex);
        printf("QUEUE FULL!!!!!\n");
        return (E_QUEUE_INSUFFICIENT_MEMORY);
    }
    // se pedido de escrita for maior que tamanho dos buffer sinaliza erro.
    if (buffersize > QUEUE_BUFFER_SIZE) {
        pthread_mutex_unlock(&queueMutex);
        printf("OVERSIZE BUFF!!!!!\n");
        return (E_QUEUE_INSUFFICIENT_MEMORY);
    }
    // Insere dados na fila
    queue_p->queue_buffer_ts[temp] = timestamp;
    memcpy((queue_p->queue_buffer[temp]), buffer_p, buffersize);
    queue_p->queue_buffer_size[temp] = buffersize;
    // Atualiza ponteiro de proxima posicao a escrever
    queue_p->next_buffer = temp;

    pthread_mutex_unlock(&queueMutex);
    return (E_OK);
}

int davint_event_dequeue(davint_event_queue_t *queue_p, uint8_t **buffer_pp, uint32_t *buffersize_p, uint32_t *timestamp_p) {
    uint8_t temp;

    // verifica se a queue existe
    if (!queue_p)
        return (E_UNDEFINED_QUEUE);

    pthread_mutex_lock(&queueMutex);
    // verifica disponibilidade de novos dados disponiveis
    if (queue_p->next_buffer == queue_p->last_buffer) {
        pthread_mutex_unlock(&queueMutex);
        return (E_EMPTY_QUEUE);
    }

    if (queue_p->last_buffer == QUEUE_BUFFER_TOTAL_NUMBER - 1) temp = 0;
    else temp = queue_p->last_buffer + 1;

    // realiza leitura de dados da queue
    *timestamp_p = queue_p->queue_buffer_ts[temp];
    *buffersize_p = queue_p->queue_buffer_size[temp];
    memcpy(*buffer_pp, queue_p->queue_buffer[temp], *buffersize_p);

    // atualiza ponteiro de ultimo posicao lida
    queue_p->last_buffer = temp;
    pthread_mutex_unlock(&queueMutex);

    return (E_OK);
}
